#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>

#include "mthread.h"

using namespace std;
/*

pthread_mutex_t mtx;
mt_mutex_t mt_mtx;

void log(char* fmt, ...) {
	char* wr;
	va_list ap;
	int fd;
	
	va_start(ap, fmt);
	vasprintf(&wr, fmt, ap);
	pthread_mutex_lock(&mtx);
	fd = open("/dev/null", O_APPEND|O_RDWR|O_CREAT|O_SYNC);
	write(fd, wr, strlen(wr));
	free(wr);
	close(fd);
	sync();
	pthread_mutex_unlock(&mtx);
}

*/

void mtworker(void* arg) {

	uint32_t vp = mt_get_vcpu();
	mt_thread_t th = mt_thread_self(); 
	char* ccc;
	
	for(int j = 0; j < 8; j++) {
		asprintf(&ccc, "%i %p\n", j, &j);
		printf("CPU: %i THREAD: %i LOOPx: %i\n", vp, th->ID, j);
		free(ccc);
		printf("CPU: %i THREAD: %i out0\n", vp, th->ID);
		_MT_SWITCH_CONTEXT(th, vp);
		printf("CPU: %i THREAD: %i in0\n", vp, th->ID);
	}
	
	int j = 0;
	
	while(true) {
		//printf("CPU: %i THREAD: %i LOOPy: %i\n", vp, th->ID, j);
		if(j++ < 128) {
			//printf("CPU: %i THREAD: %i out\n", vp, th->ID);
			_MT_SWITCH_CONTEXT(th, vp);
			//printf("CPU: %i THREAD: %i in\n", vp, th->ID);
		} else
			break;
		//printf("CPU: %i THREAD: %i inx\n", vp, th->ID);
	}
	printf("CPU: %i THREAD: %i leaving\n", vp, th->ID, j);
	return;
}



void* pworker(void* xxx) {
	printf("CPUx: pworker entered.\n");
#if defined(__i386__)
	uint32_t arg = (uint32_t)xxx;
#elif defined(__amd64__)
	uint32_t arg = (uint64_t)xxx;
#else
#error unsupported platform
#endif	
	uint32_t vp = vp_init(arg);
	mt_thread_t th = mt_thread_self(); 

	while(1) {
		for(int i = 0; i < 512; i++) {
			printf("CPUx: preccreate.\n");
			mt_thread_create(mtworker, (void*)vp);
			printf("CPUx: aftetccreate.\n");
			_MT_SWITCH_CONTEXT(th, vp);
			printf("CPUx: afterswitch.	g \n");
		
		}
		
		mt_join_all();
	}
	
	printf("CPU: %i Halting\n", vp);
	vp_destroy();
	printf("CPU: %i Halted\n", vp);
	//pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
	/*while(1) {pworker(NULL);};
	return EXIT_SUCCESS;*/
	
	pthread_t pt[128];
	pthread_attr_t pta[128];
	
	while(true) {
		for(uint32_t i = 0; i < 4; i++) {
			cout << "starting new cpu "<< i <<"\n";
			pthread_attr_init(&pta[i]);
			pthread_attr_setstacksize(&pta[i], 1024*16);
			pthread_create(&pt[i], &pta[i], pworker, (void*)i);
			
		}
	
		for(int i = 0; i < 2; i++) {
			pthread_join(pt[i], NULL);
		}
		
	}
	
  	return EXIT_SUCCESS;
}
